﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using IPC.Communication;
using IPC.Communication.BasicFramework;
using IPC.Communication.Profinet.AllenBradley;

namespace IPC.Communication.Profinet.AllenBradley
{
    public class AllenBradleyHelper
    {
	    public const byte CIP_READ_DATA = 76;

	    public const int CIP_WRITE_DATA = 77;

	    public const int CIP_READ_WRITE_DATA = 78;

	    public const int CIP_READ_FRAGMENT = 82;

	    public const int CIP_WRITE_FRAGMENT = 83;

	    public const byte CIP_READ_LIST = 85;

	    public const int CIP_MULTIREAD_DATA = 4096;

	    public const ushort CIP_Type_Bool = 193;

	    public const ushort CIP_Type_Byte = 194;

	    public const ushort CIP_Type_Word = 195;

	    public const ushort CIP_Type_DWord = 196;

	    public const ushort CIP_Type_LInt = 197;

	    public const ushort CIP_Type_USInt = 198;

	    public const ushort CIP_Type_UInt = 199;

	    public const ushort CIP_Type_UDint = 200;

	    public const ushort CIP_Type_ULint = 201;

	    public const ushort CIP_Type_Real = 202;

	    public const ushort CIP_Type_Double = 203;

	    public const ushort CIP_Type_Struct = 204;

	    public const ushort CIP_Type_String = 208;

	    public const ushort CIP_Type_D1 = 209;

	    public const ushort CIP_Type_D2 = 210;

	    public const ushort CIP_Type_D3 = 211;

	    public const ushort CIP_Type_BitArray = 211;

	    private static byte[] BuildRequestPathCommand(string address, bool isConnectedAddress = false)
	    {
		    using (MemoryStream memoryStream = new MemoryStream())
		    {
			    string[] array = address.Split(new char[1]
			    {
				    '.'
			    }, StringSplitOptions.RemoveEmptyEntries);
			    for (int i = 0; i < array.Length; i++)
			    {
				    string text = string.Empty;
				    int num = array[i].IndexOf('[');
				    int num2 = array[i].IndexOf(']');
				    if (num > 0 && num2 > 0 && num2 > num)
				    {
					    text = array[i].Substring(num + 1, num2 - num - 1);
					    array[i] = array[i].Substring(0, num);
				    }
				    memoryStream.WriteByte(145);
				    byte[] bytes = Encoding.UTF8.GetBytes(array[i]);
				    memoryStream.WriteByte((byte)bytes.Length);
				    memoryStream.Write(bytes, 0, bytes.Length);
				    if (bytes.Length % 2 == 1)
				    {
					    memoryStream.WriteByte(0);
				    }
				    if (!string.IsNullOrEmpty(text))
				    {
					    string[] array2 = text.Split(new char[1]
					    {
						    ','
					    }, StringSplitOptions.RemoveEmptyEntries);
					    for (int j = 0; j < array2.Length; j++)
					    {
						    int num3 = Convert.ToInt32(array2[j]);
						    if (num3 < 256 && !isConnectedAddress)
						    {
							    memoryStream.WriteByte(40);
							    memoryStream.WriteByte((byte)num3);
						    }
						    else
						    {
							    memoryStream.WriteByte(41);
							    memoryStream.WriteByte(0);
							    memoryStream.WriteByte(BitConverter.GetBytes(num3)[0]);
							    memoryStream.WriteByte(BitConverter.GetBytes(num3)[1]);
						    }
					    }
				    }
			    }
			    return memoryStream.ToArray();
		    }
	    }

	    public static string ParseRequestPathCommand(byte[] pathCommand)
	    {
		    StringBuilder stringBuilder = new StringBuilder();
		    for (int i = 0; i < pathCommand.Length; i++)
		    {
			    if (pathCommand[i] != 145)
			    {
				    continue;
			    }
			    string text = Encoding.UTF8.GetString(pathCommand, i + 2, pathCommand[i + 1]).TrimEnd(default(char));
			    stringBuilder.Append(text);
			    int num = 2 + text.Length;
			    if (text.Length % 2 == 1)
			    {
				    num++;
			    }
			    if (pathCommand.Length > num + i)
			    {
				    if (pathCommand[i + num] == 40)
				    {
					    stringBuilder.Append(String.Format("[{0}]", pathCommand[i + num + 1]));
				    }
				    else if (pathCommand[i + num] == 41)
				    {
                        stringBuilder.Append(String.Format("[{0}]", BitConverter.ToUInt16(pathCommand, i + num + 2)));
				    }
			    }
			    stringBuilder.Append(".");
		    }
		    if (stringBuilder[stringBuilder.Length - 1] == '.')
		    {
			    stringBuilder.Remove(stringBuilder.Length - 1, 1);
		    }
		    return stringBuilder.ToString();
	    }

	    public static byte[] GetEnumeratorCommand(ushort startInstance)
	    {
		    return new byte[14]
		    {
			    85,
			    3,
			    32,
			    107,
			    37,
			    0,
			    BitConverter.GetBytes(startInstance)[0],
			    BitConverter.GetBytes(startInstance)[1],
			    2,
			    0,
			    1,
			    0,
			    2,
			    0
		    };
	    }

	    public static byte[] GetStructHandleCommand(ushort symbolType)
	    {
		    byte[] array = new byte[18];
		    byte[] bytes = BitConverter.GetBytes(symbolType);
		    bytes[1] = (byte)(bytes[1] & 0xF);
		    array[0] = 3;
		    array[1] = 3;
		    array[2] = 32;
		    array[3] = 108;
		    array[4] = 37;
		    array[5] = 0;
		    array[6] = bytes[0];
		    array[7] = bytes[1];
		    array[8] = 4;
		    array[9] = 0;
		    array[10] = 4;
		    array[11] = 0;
		    array[12] = 5;
		    array[13] = 0;
		    array[14] = 2;
		    array[15] = 0;
		    array[16] = 1;
		    array[17] = 0;
		    return array;
	    }

	    public static byte[] GetStructItemNameType(ushort symbolType, AbStructHandle structHandle)
	    {
		    byte[] array = new byte[14];
		    ushort value = (ushort)(structHandle.TemplateObjectDefinitionSize * 4 - 21);
		    byte[] bytes = BitConverter.GetBytes(symbolType);
		    bytes[1] = (byte)(bytes[1] & 0xF);
		    byte[] bytes2 = BitConverter.GetBytes(0);
		    byte[] bytes3 = BitConverter.GetBytes(value);
		    array[0] = 76;
		    array[1] = 3;
		    array[2] = 32;
		    array[3] = 108;
		    array[4] = 37;
		    array[5] = 0;
		    array[6] = bytes[0];
		    array[7] = bytes[1];
		    array[8] = bytes2[0];
		    array[9] = bytes2[1];
		    array[10] = bytes2[2];
		    array[11] = bytes2[3];
		    array[12] = bytes3[0];
		    array[13] = bytes3[1];
		    return array;
	    }

	    public static byte[] PackRequestHeader(ushort command, uint session, byte[] commandSpecificData)
	    {
		    byte[] array = new byte[commandSpecificData.Length + 24];
		    Array.Copy(commandSpecificData, 0, array, 24, commandSpecificData.Length);
		    BitConverter.GetBytes(command).CopyTo(array, 0);
		    BitConverter.GetBytes(session).CopyTo(array, 4);
		    BitConverter.GetBytes((ushort)commandSpecificData.Length).CopyTo(array, 2);
		    return array;
	    }

	    public static byte[] PackRequestHeader(ushort command, uint error, uint session, byte[] commandSpecificData)
	    {
		    byte[] array = PackRequestHeader(command, session, commandSpecificData);
		    BitConverter.GetBytes(error).CopyTo(array, 8);
		    return array;
	    }

	    public static byte[] PackRequsetRead(string address, int length, bool isConnectedAddress = false)
	    {
		    byte[] array = new byte[1024];
		    int num = 0;
		    array[num++] = 76;
		    num++;
		    byte[] array2 = BuildRequestPathCommand(address, isConnectedAddress);
		    array2.CopyTo(array, num);
		    num += array2.Length;
		    array[1] = (byte)((num - 2) / 2);
		    array[num++] = BitConverter.GetBytes(length)[0];
		    array[num++] = BitConverter.GetBytes(length)[1];
		    byte[] array3 = new byte[num];
		    Array.Copy(array, 0, array3, 0, num);
		    return array3;
	    }

	    public static byte[] PackRequestReadSegment(string address, int startIndex, int length)
	    {
		    byte[] array = new byte[1024];
		    int num = 0;
		    array[num++] = 82;
		    num++;
		    byte[] array2 = BuildRequestPathCommand(address);
		    array2.CopyTo(array, num);
		    num += array2.Length;
		    array[1] = (byte)((num - 2) / 2);
		    array[num++] = BitConverter.GetBytes(length)[0];
		    array[num++] = BitConverter.GetBytes(length)[1];
		    array[num++] = BitConverter.GetBytes(startIndex)[0];
		    array[num++] = BitConverter.GetBytes(startIndex)[1];
		    array[num++] = BitConverter.GetBytes(startIndex)[2];
		    array[num++] = BitConverter.GetBytes(startIndex)[3];
		    byte[] array3 = new byte[num];
		    Array.Copy(array, 0, array3, 0, num);
		    return array3;
	    }

	    public static byte[] PackRequestWrite(string address, ushort typeCode, byte[] value, int length = 1, bool isConnectedAddress = false)
	    {
		    byte[] array = new byte[1024];
		    int num = 0;
		    array[num++] = 77;
		    num++;
		    byte[] array2 = BuildRequestPathCommand(address, isConnectedAddress);
		    array2.CopyTo(array, num);
		    num += array2.Length;
		    array[1] = (byte)((num - 2) / 2);
		    array[num++] = BitConverter.GetBytes(typeCode)[0];
		    array[num++] = BitConverter.GetBytes(typeCode)[1];
		    array[num++] = BitConverter.GetBytes(length)[0];
		    array[num++] = BitConverter.GetBytes(length)[1];
		    value.CopyTo(array, num);
		    num += value.Length;
		    byte[] array3 = new byte[num];
		    Array.Copy(array, 0, array3, 0, num);
		    return array3;
	    }

	    public static string AnalysisArrayIndex(string address, out int arrayIndex)
	    {
		    arrayIndex = 0;
		    if (!address.EndsWith("]"))
		    {
			    return address;
		    }
		    int num = address.LastIndexOf('[');
		    if (num < 0)
		    {
			    return address;
		    }
		    address = address.Remove(address.Length - 1);
		    arrayIndex = int.Parse(address.Substring(num + 1));
		    address = address.Substring(0, num);
		    return address;
	    }

	    public static byte[] PackRequestWrite(string address, bool value)
	    {
            int arrayIndex = 0;
		    address = AnalysisArrayIndex(address, out arrayIndex);
		    address = address + "[" + (arrayIndex / 32).ToString() + "]";
		    int value2 = 0;
		    int value3 = -1;
		    if (value)
		    {
			    value2 = 1 << arrayIndex;
		    }
		    else
		    {
			    value3 = ~(1 << arrayIndex);
		    }
		    byte[] array = new byte[1024];
		    int num = 0;
		    array[num++] = 78;
		    num++;
		    byte[] array2 = BuildRequestPathCommand(address);
		    array2.CopyTo(array, num);
		    num += array2.Length;
		    array[1] = (byte)((num - 2) / 2);
		    array[num++] = 4;
		    array[num++] = 0;
		    BitConverter.GetBytes(value2).CopyTo(array, num);
		    num += 4;
		    BitConverter.GetBytes(value3).CopyTo(array, num);
		    num += 4;
		    byte[] array3 = new byte[num];
		    Array.Copy(array, 0, array3, 0, num);
		    return array3;
	    }

	    public static byte[] PackCommandService(byte[] portSlot, params byte[][] cips)
	    {
		    MemoryStream memoryStream = new MemoryStream();
		    memoryStream.WriteByte(178);
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(82);
		    memoryStream.WriteByte(2);
		    memoryStream.WriteByte(32);
		    memoryStream.WriteByte(6);
		    memoryStream.WriteByte(36);
		    memoryStream.WriteByte(1);
		    memoryStream.WriteByte(10);
		    memoryStream.WriteByte(240);
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(0);
		    int num = 0;
		    if (cips.Length == 1)
		    {
			    memoryStream.Write(cips[0], 0, cips[0].Length);
			    num += cips[0].Length;
		    }
		    else
		    {
			    memoryStream.WriteByte(10);
			    memoryStream.WriteByte(2);
			    memoryStream.WriteByte(32);
			    memoryStream.WriteByte(2);
			    memoryStream.WriteByte(36);
			    memoryStream.WriteByte(1);
			    num += 8;
			    memoryStream.Write(BitConverter.GetBytes((ushort)cips.Length), 0, 2);
			    ushort num2 = (ushort)(2 + 2 * cips.Length);
			    num += 2 * cips.Length;
			    for (int i = 0; i < cips.Length; i++)
			    {
				    memoryStream.Write(BitConverter.GetBytes(num2), 0, 2);
				    num2 = (ushort)(num2 + cips[i].Length);
			    }
			    for (int j = 0; j < cips.Length; j++)
			    {
				    memoryStream.Write(cips[j], 0, cips[j].Length);
				    num += cips[j].Length;
			    }
		    }
		    memoryStream.WriteByte((byte)((portSlot.Length + 1) / 2));
		    memoryStream.WriteByte(0);
		    memoryStream.Write(portSlot, 0, portSlot.Length);
		    if (portSlot.Length % 2 == 1)
		    {
			    memoryStream.WriteByte(0);
		    }
		    byte[] array = memoryStream.ToArray();
		    BitConverter.GetBytes((short)num).CopyTo(array, 12);
		    BitConverter.GetBytes((short)(array.Length - 4)).CopyTo(array, 2);
		    return array;
	    }

	    public static byte[] PackCleanCommandService(byte[] portSlot, params byte[][] cips)
	    {
		    MemoryStream memoryStream = new MemoryStream();
		    memoryStream.WriteByte(178);
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(0);
		    if (cips.Length == 1)
		    {
			    memoryStream.Write(cips[0], 0, cips[0].Length);
		    }
		    else
		    {
			    memoryStream.WriteByte(10);
			    memoryStream.WriteByte(2);
			    memoryStream.WriteByte(32);
			    memoryStream.WriteByte(2);
			    memoryStream.WriteByte(36);
			    memoryStream.WriteByte(1);
			    memoryStream.Write(BitConverter.GetBytes((ushort)cips.Length), 0, 2);
			    ushort num = (ushort)(2 + 2 * cips.Length);
			    for (int i = 0; i < cips.Length; i++)
			    {
				    memoryStream.Write(BitConverter.GetBytes(num), 0, 2);
				    num = (ushort)(num + cips[i].Length);
			    }
			    for (int j = 0; j < cips.Length; j++)
			    {
				    memoryStream.Write(cips[j], 0, cips[j].Length);
			    }
		    }
		    memoryStream.WriteByte((byte)((portSlot.Length + 1) / 2));
		    memoryStream.WriteByte(0);
		    memoryStream.Write(portSlot, 0, portSlot.Length);
		    if (portSlot.Length % 2 == 1)
		    {
			    memoryStream.WriteByte(0);
		    }
		    byte[] array = memoryStream.ToArray();
		    BitConverter.GetBytes((short)(array.Length - 4)).CopyTo(array, 2);
		    return array;
	    }

	    public static byte[] PackCommandGetAttributesAll(byte[] portSlot, uint sessionHandle)
	    {
		    byte[] commandSpecificData = PackCommandSpecificData(new byte[4], PackCommandService(portSlot, new byte[6]
		    {
			    1,
			    2,
			    32,
			    1,
			    36,
			    1
		    }));
		    return PackRequestHeader(111, sessionHandle, commandSpecificData);
	    }

	    public static byte[] PackCommandResponse(byte[] data, bool isRead)
	    {
		    if (data == null)
		    {
			    return new byte[6]
			    {
				    0,
				    0,
				    4,
				    0,
				    0,
				    0
			    };
		    }
		    return SoftBasic.SpliceArray<byte>(new byte[6]
		    {
			    (byte)(isRead ? 204 : 205),
			    0,
			    0,
			    0,
			    0,
			    0
		    }, data);
	    }

	    public static byte[] PackCommandSpecificData(params byte[][] service)
	    {
		    MemoryStream memoryStream = new MemoryStream();
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(1);
		    memoryStream.WriteByte(0);
		    memoryStream.WriteByte(BitConverter.GetBytes(service.Length)[0]);
		    memoryStream.WriteByte(BitConverter.GetBytes(service.Length)[1]);
		    for (int i = 0; i < service.Length; i++)
		    {
			    memoryStream.Write(service[i], 0, service[i].Length);
		    }
		    return memoryStream.ToArray();
	    }

	    public static byte[] PackCommandSingleService(byte[] command)
	    {
		    if (command == null)
		    {
			    command = new byte[0];
		    }
		    byte[] array = new byte[4 + command.Length];
		    array[0] = 178;
		    array[1] = 0;
		    array[2] = BitConverter.GetBytes(command.Length)[0];
		    array[3] = BitConverter.GetBytes(command.Length)[1];
		    command.CopyTo(array, 4);
		    return array;
	    }

	    public static byte[] RegisterSessionHandle()
	    {
		    byte[] commandSpecificData = new byte[4]
		    {
			    1,
			    0,
			    0,
			    0
		    };
		    return PackRequestHeader(101, 0u, commandSpecificData);
	    }

	    public static byte[] UnRegisterSessionHandle(uint sessionHandle)
	    {
		    return PackRequestHeader(102, sessionHandle, new byte[0]);
	    }

	    public static OperateResult CheckResponse(byte[] response)
	    {
		    try
		    {
			    int num = BitConverter.ToInt32(response, 8);
			    if (num == 0)
			    {
				    return OperateResult.CreateSuccessResult();
			    }
			    string empty = string.Empty;
			    switch (num)
			    {
			    case 1:
				    empty = StringResources.Language.AllenBradleySessionStatus01;
				    break;
			    case 2:
				    empty = StringResources.Language.AllenBradleySessionStatus02;
				    break;
			    case 3:
				    empty = StringResources.Language.AllenBradleySessionStatus03;
				    break;
			    case 100:
				    empty = StringResources.Language.AllenBradleySessionStatus64;
				    break;
			    case 101:
				    empty = StringResources.Language.AllenBradleySessionStatus65;
				    break;
			    case 105:
				    empty = StringResources.Language.AllenBradleySessionStatus69;
				    break;
			    default:
				    empty = StringResources.Language.UnknownError;
				    break;
			    }
			    return new OperateResult(num, empty);
		    }
		    catch (Exception ex)
		    {
			    return new OperateResult(ex.Message);
		    }
	    }

	    public static OperateResult<byte[], ushort, bool> ExtractActualData(byte[] response, bool isRead)
	    {
		    List<byte> list = new List<byte>();
		    int num = 38;
		    bool value = false;
		    ushort value2 = 0;
		    ushort num2 = BitConverter.ToUInt16(response, 38);
		    if (BitConverter.ToInt32(response, 40) == 138)
		    {
			    num = 44;
			    int num3 = BitConverter.ToUInt16(response, num);
			    for (int i = 0; i < num3; i++)
			    {
				    int num4 = BitConverter.ToUInt16(response, num + 2 + i * 2) + num;
				    int num5 = (i == num3 - 1) ? response.Length : (BitConverter.ToUInt16(response, num + 4 + i * 2) + num);
				    ushort num6 = BitConverter.ToUInt16(response, num4 + 2);
				    switch (num6)
				    {
				    case 4:
					    return new OperateResult<byte[], ushort, bool>
					    {
						    ErrorCode = num6,
						    Message = StringResources.Language.AllenBradley04
					    };
				    case 5:
					    return new OperateResult<byte[], ushort, bool>
					    {
						    ErrorCode = num6,
						    Message = StringResources.Language.AllenBradley05
					    };
				    case 6:
					    if (response[num + 2] == 210 || response[num + 2] == 204)
					    {
						    return new OperateResult<byte[], ushort, bool>
						    {
							    ErrorCode = num6,
							    Message = StringResources.Language.AllenBradley06
						    };
					    }
					    break;
				    case 10:
					    return new OperateResult<byte[], ushort, bool>
					    {
						    ErrorCode = num6,
						    Message = StringResources.Language.AllenBradley0A
					    };
				    case 19:
					    return new OperateResult<byte[], ushort, bool>
					    {
						    ErrorCode = num6,
						    Message = StringResources.Language.AllenBradley13
					    };
				    case 28:
					    return new OperateResult<byte[], ushort, bool>
					    {
						    ErrorCode = num6,
						    Message = StringResources.Language.AllenBradley1C
					    };
				    case 30:
					    return new OperateResult<byte[], ushort, bool>
					    {
						    ErrorCode = num6,
						    Message = StringResources.Language.AllenBradley1E
					    };
				    case 38:
					    return new OperateResult<byte[], ushort, bool>
					    {
						    ErrorCode = num6,
						    Message = StringResources.Language.AllenBradley26
					    };
				    default:
					    return new OperateResult<byte[], ushort, bool>
					    {
						    ErrorCode = num6,
						    Message = StringResources.Language.UnknownError
					    };
				    case 0:
					    break;
				    }
				    if (isRead)
				    {
					    for (int j = num4 + 6; j < num5; j++)
					    {
						    list.Add(response[j]);
					    }
				    }
			    }
		    }
		    else
		    {
			    byte b = response[num + 4];
			    switch (b)
			    {
			    case 4:
				    return new OperateResult<byte[], ushort, bool>
				    {
					    ErrorCode = b,
					    Message = StringResources.Language.AllenBradley04
				    };
			    case 5:
				    return new OperateResult<byte[], ushort, bool>
				    {
					    ErrorCode = b,
					    Message = StringResources.Language.AllenBradley05
				    };
			    case 6:
				    value = true;
				    break;
			    case 10:
				    return new OperateResult<byte[], ushort, bool>
				    {
					    ErrorCode = b,
					    Message = StringResources.Language.AllenBradley0A
				    };
			    case 19:
				    return new OperateResult<byte[], ushort, bool>
				    {
					    ErrorCode = b,
					    Message = StringResources.Language.AllenBradley13
				    };
			    case 28:
				    return new OperateResult<byte[], ushort, bool>
				    {
					    ErrorCode = b,
					    Message = StringResources.Language.AllenBradley1C
				    };
			    case 30:
				    return new OperateResult<byte[], ushort, bool>
				    {
					    ErrorCode = b,
					    Message = StringResources.Language.AllenBradley1E
				    };
			    case 32:
				    return new OperateResult<byte[], ushort, bool>
				    {
					    ErrorCode = b,
					    Message = StringResources.Language.AllenBradley20
				    };
			    case 38:
				    return new OperateResult<byte[], ushort, bool>
				    {
					    ErrorCode = b,
					    Message = StringResources.Language.AllenBradley26
				    };
			    default:
				    return new OperateResult<byte[], ushort, bool>
				    {
					    ErrorCode = b,
					    Message = StringResources.Language.UnknownError
				    };
			    case 0:
				    break;
			    }
			    if (response[num + 2] == 205 || response[num + 2] == 211)
			    {
				    return OperateResult.CreateSuccessResult(list.ToArray(), value2, value);
			    }
			    if (response[num + 2] == 204 || response[num + 2] == 210)
			    {
				    for (int k = num + 8; k < num + 2 + num2; k++)
				    {
					    list.Add(response[k]);
				    }
				    value2 = BitConverter.ToUInt16(response, num + 6);
			    }
			    else if (response[num + 2] == 213)
			    {
				    for (int l = num + 6; l < num + 2 + num2; l++)
				    {
					    list.Add(response[l]);
				    }
			    }
		    }
		    return OperateResult.CreateSuccessResult(list.ToArray(), value2, value);
	    }
    }
}
